#include "tlvs.h"

//wow the code is so beautiful and sexy!

TlvPacket &Tlv0x1::pack(const uint & uin)
{
    writeShort(1); // _ip_ver
    writeInt(Util::getRandomNumber());
    writeInt(uin);
    writeInt(Util::getUTCTime());
    writeRaw(QQDeviceConfig::getInstance().localIP);
    writeShort(0);
    return *this;
}

short Tlv0x2::sigVer = 0;

TlvPacket &Tlv0x2::pack(const QString &captchaCode, const QByteArray &captchaToken)
{
    writeShort(sigVer);
    writeBytes(captchaCode.toLatin1(),LengthType::SHORT);
    writeBytes(captchaToken,LengthType::SHORT);
    return *this;
}

int Tlv0x8::localId = 2052;

TlvPacket &Tlv0x8::pack()
{
    writeShort(0);
    writeInt(localId);
    writeShort(0);
    return *this;
}

TlvPacket &Tlv0x18::pack(const uint &uin)
{
    writeShort(1); //_ping_version
    writeInt(1536); //_sso_version
    writeInt(QQDeviceConfig::getInstance().appId);
    writeInt(QQDeviceConfig::getInstance().appClientVersion);
    writeInt(uin);
    writeShort(0);//constant1_always_0
    writeShort(0);
    return *this;
}

long Tlv0x106::salt = 0;
bool Tlv0x106::isGuidAvailable = true;

TlvPacket &Tlv0x106::pack(const uint & uin,const QByteArray & password,const LoginType & loginType)
{
    this->password = password;
    this->uin = uin;
    //prepare for the getKey()

    writeShort(4);
    writeInt(Util::getRandomNumber());
    writeInt(5);//ssoVer
    writeInt(QQDeviceConfig::getInstance().appId);
    writeInt(QQDeviceConfig::getInstance().appClientVersion);
    writeLong(uin==0?salt:uin);
    writeInt(Util::getUTCTime());
    writeRaw(QByteArray(4,0));// ip ,no need to write actual ip
    writeByte(1);//n5_always_1
    writeRaw(Util::md5(password));
    writeRaw(QQDeviceConfig::getInstance().tgtgKey);
    writeInt(0);
    writeByte(isGuidAvailable);
    if(isGuidAvailable && QQDeviceConfig::getInstance().guid.size()!=16)abort();
    //check if the guid.size == 16
    writeRaw(QQDeviceConfig::getInstance().guid);
    writeInt(QQDeviceConfig::getInstance().subAppId);
    writeInt(loginType);
    writeBytes(Util::getBytes((quint64)uin),LengthType::SHORT);
    writeShort(0);
    return *this;
}

QByteArray Tlv0x106::getKey()
{
    //QByteArray ret;
    //ret.push_back(Util::md5(password));
    //ret.push_back(Util::getBytes((quint64)uin));
    return Util::md5(Util::md5(password)+QByteArray(4,0)+Util::getBytes((int)uin));
}

QList<quint64> Tlv0x116::appIdList = {1600000226L};
//the grammer is so amazing!!!

TlvPacket &Tlv0x116::pack()
{
    writeByte(0); // _ver
    writeInt(QQDeviceConfig::getInstance().miscBitMap); // 184024956
    writeInt(QQDeviceConfig::getInstance().subSigMap); // 66560
    writeByte(appIdList.size());
    foreach (auto item, appIdList) {
        writeInt(item);
    }
    return *this;
}

TlvPacket &Tlv0x100::pack()
{
    writeShort(1);//db_buf_ver
    writeInt(5);//sso_ver
    writeInt(QQDeviceConfig::getInstance().appId);
    writeInt(QQDeviceConfig::getInstance().subAppId);
    writeInt(QQDeviceConfig::getInstance().appClientVersion);
    writeInt(34869472); // sigMap, 34869472?
    return *this;
}

int Tlv0x107::picType = 0;

TlvPacket &Tlv0x107::pack()
{
    writeShort(picType);
    writeByte(0);//const1_always_0
    writeShort(0);//const2_always_0
    writeByte(1);//const3_always_1
    return *this;
}

TlvPacket &Tlv0x108::pack()
{
    writeRaw(QQDeviceConfig::getInstance().ksid);
    return *this;
}

int Tlv0x17a::value = 9;

TlvPacket &Tlv0x17a::pack()
{
    writeInt(value);
    return *this;
}

QByteArray Tlv0x197::value = QByteArray::fromHex("00");

TlvPacket &Tlv0x197::pack()
{
    writeRaw(value);
    return *this;
}

int Tlv0x19e::value = 0;

TlvPacket &Tlv0x19e::pack()
{
    writeShort(1);
    writeByte(value);
    return *this;
}

TlvPacket &Tlv0x142::pack()
{
    writeShort(0);//_version
    writeBytes(QQDeviceConfig::getInstance().apkID,LengthType::SHORT,32);
    return *this;
}

TlvPacket &Tlv0x144::pack(NetworkType networkType)
{
    writeShort(5);
    Tlv0x109(this).pack().release();
    Tlv0x52d(this).pack().release();
    Tlv0x124(this).pack(networkType).release();
    Tlv0x128(this).pack().release();
    Tlv0x16e(this).pack().release();
    return *this;
}

QByteArray Tlv0x144::getKey()
{
    return QQDeviceConfig::getInstance().tgtgKey;
}

TlvPacket &Tlv0x109::pack()
{
    writeRaw(Util::md5(QQDeviceConfig::getInstance().androidId));
    return *this;
}

TlvPacket &Tlv0x52d::pack()
{
    /*
    writeProtobufBytes(1,QQDeviceConfig::getInstance().bootloader);
    writeProtobufBytes(2,QQDeviceConfig::getInstance().procVersion);
    writeProtobufBytes(3,QQDeviceConfig::getInstance().codeName);
    writeProtobufBytes(4,QQDeviceConfig::getInstance().incremental);
    writeProtobufBytes(5,QQDeviceConfig::getInstance().fingerprint);
    writeProtobufBytes(6,QQDeviceConfig::getInstance().bootID);
    writeProtobufBytes(7,QQDeviceConfig::getInstance().androidId);
    writeProtobufBytes(8,QQDeviceConfig::getInstance().baseBand);
    writeProtobufBytes(9,QQDeviceConfig::getInstance().incremental);
    */

    writeRaw(QByteArray::fromStdString(QQDeviceConfig::getInstance().deviceData.SerializeAsString()));
    return *this;
    /*
        bootloader,
        procVersion,
        version.codename,
        version.incremental,
        fingerprint,
        bootId,
        androidId,
        baseBand,
        version.incremental
    */
}

QByteArray Tlv0x124::unknown = QByteArray();

TlvPacket &Tlv0x124::pack(NetworkType networkType)
{
    writeBytes(QQDeviceConfig::getInstance().osType,LengthType::SHORT,16);
    writeBytes(QQDeviceConfig::getInstance().release,LengthType::SHORT,16);
    writeShort(networkType);
    writeBytes(QQDeviceConfig::getInstance().simInfo,LengthType::SHORT,16);
    writeBytes(unknown,LengthType::SHORT,32);
    writeBytes(QQDeviceConfig::getInstance().apn,LengthType::SHORT,16);
    return *this;
}

TlvPacket &Tlv0x128::pack()
{
    writeShort(0);
    writeByte(0);//isGuidFromFileNull
    writeByte(1);//isGuidAvailable
    writeByte(0);//isGuidChanged
    writeRaw(QByteArray::fromHex("11 00 00 00"));//guidFlag
    writeBytes(QQDeviceConfig::getInstance().model,LengthType::SHORT,32);
    writeBytes(QQDeviceConfig::getInstance().guid,LengthType::SHORT,16);
    writeBytes(QQDeviceConfig::getInstance().brand,LengthType::SHORT,16);
    return *this;
}

TlvPacket &Tlv0x16e::pack()
{
    writeRaw(QQDeviceConfig::getInstance().model);
    return *this;
}

TlvPacket &Tlv0x145::pack()
{
    writeRaw(QQDeviceConfig::getInstance().guid);
    return *this;
}

TlvPacket &Tlv0x147::pack()
{
    writeInt(QQDeviceConfig::getInstance().appId);
    writeBytes(QQDeviceConfig::getInstance().apkVersionName,LengthType::SHORT,32);
    writeBytes(QQDeviceConfig::getInstance().apkSignatureMd5,LengthType::SHORT,32);
    return *this;
}

int Tlv0x166::imageType = 1;

TlvPacket &Tlv0x166::pack()
{
    writeByte(imageType);
    return *this;
}

TlvPacket &Tlv0x154::pack(uint ssoSequenceId)
{
    writeInt(ssoSequenceId);
    return *this;
}

TlvPacket &Tlv0x141::pack(NetworkType networkType)
{
    writeShort(1);
    writeBytes(QQDeviceConfig::getInstance().simInfo,LengthType::SHORT);
    writeShort(networkType);
    writeBytes(QQDeviceConfig::getInstance().apn,LengthType::SHORT);
    return *this;
}

TlvPacket &Tlv0x511::pack()
{
    const QStringList & domains = QQDeviceConfig::getInstance().domains;
    writeShort(domains.size());
    foreach (auto item, domains) {
        writeByte(1);
        writeBytes(item.toLatin1(),LengthType::SHORT);
        //TODO ADD SOME SUPPORT
    }
    return *this;
}

TlvPacket &Tlv0x185::pack()
{
    writeByte(1);
    writeByte(1);
    return *this;
}

TlvPacket &Tlv0x187::pack()
{
    writeRaw(Util::md5(QQDeviceConfig::getInstance().macAddress));
    return *this;
}

TlvPacket &Tlv0x188::pack()
{
    writeRaw(Util::md5(QQDeviceConfig::getInstance().androidId));
    return *this;
}

TlvPacket &Tlv0x193::pack(QString ticket)
{
    writeRaw(ticket.toLatin1());
    return *this;
}

TlvPacket &Tlv0x194::pack()
{
    writeRaw(QQDeviceConfig::getInstance().imsiMd5);
    return *this;
}

int Tlv0x191::K = 0x82;

TlvPacket &Tlv0x191::pack()
{
    writeByte(K);
    return *this;
}

TlvPacket &Tlv0x202::pack()
{
    writeBytes(QQDeviceConfig::getInstance().wifiBSSID,LengthType::SHORT,16);
    writeBytes(QQDeviceConfig::getInstance().wifiSSID,LengthType::SHORT,32);
    return *this;
}

quint64 Tlv0x177::unknown1 = 1571193922L;
QString Tlv0x177::unknown2 = "6.0.0.2413";

TlvPacket &Tlv0x177::pack()
{
    writeByte(1);
    writeInt(unknown1);
    writeBytes(unknown2.toLatin1(),LengthType::SHORT);
    if(getSize() != 0x11)abort();//the size is wrong.
    return *this;
}

TlvPacket &Tlv0x516::pack()
{
    writeInt(0);//sourceType
    return *this;
}

TlvPacket &Tlv0x521::pack()
{
    writeInt(0);//productType
    writeShort(0);//unknown
    return *this;
}
/*
TlvPacket &Tlv0x536::pack(const QByteArray &loginExtraData)
{
    writeRaw(loginExtraData);
    return *this;
}
*/
TlvPacket &Tlv0x525::pack()
{
    writeShort(1);
    Tlv0x536(this).pack().release();
    return *this;
}

TlvPacket &Tlv0x536::pack()
{
    writeByte(1);
    writeByte(0);
    return *this;
}
